#pragma once

#include <iostream>
#include <pthread.h>
#include <vector>
#include "Mutex.hpp"
#include "Sem.hpp"

using namespace SemMoudule;
using namespace MutexModule;

const int gcap = 10;

template <class T>
class RingQueue
{
public:
    RingQueue(int cap = gcap)
        : _cap(cap), _rq(_cap), _cindex(0), _pindex(0), _sem_blank(_cap), _sem_data(0)
    {
    }

    // 生产者生产数据入队列
    void Entry(const T &in)
    {
        // 单生产者的工作：先检查_sem_blank是否为0，不为0就对该信号量进行--操作，为0就阻塞该线程。
        //                将数据放入数组，数组下标++，取模保证不越界。再对_sem_data进行V操作。
        _sem_blank.P();
        {
            // 维护生产者与生产者之间的互斥关系的时候：锁加在P操作之后，因为先对资源进行预定，再来竞争锁的效率更高
            _pmutex.Lock();
            _rq[_pindex] = in;
            _pindex++;
            _pindex %= _cap;
            _pmutex.Unlock();
        }
        _sem_data.V();
    }

    // 消费者拿数据出队列(输出型参数来接收出队列数据)
    void Pop(T *data)
    {
        _sem_data.P();
        {
            _cmutex.Lock();
            *data = _rq[_cindex];
            _cindex++;
            _cindex %= _cap;
            _cmutex.Unlock();
        }
        _sem_blank.V();
    }

    ~RingQueue()
    {
    }

private:
    // 基础数据结构, 用vector来模拟环形队列
    std::vector<T> _rq;
    // 环形队列容量
    int _cap;

    // 生产者和消费者的下标
    int _cindex;
    int _pindex;

    // 生产者，消费者的信号量
    Sem _sem_blank;
    Sem _sem_data;

    // 维护生产者之间的锁和维护消费者之间的锁
    Mutex _cmutex;
    Mutex _pmutex;
};